package cn.edu.ctbu.config;

import cn.edu.ctbu.service.impl.UserDetailsServiceImpl;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import javax.annotation.Resource;

/**
 * <p>
 * WebSecurityConfig 类是 Spring Security 的配置类，用于定义认证和授权的安全策略。
 * 该类通过继承 WebSecurityConfigurerAdapter (Spring Security 5.7.0 + 中弃用，无法使用) 来实现安全配置。
 * </p>
 *
 * 功能概述：
 * - 配置自定义的 UserDetailsService，用于从数据库加载用户信息进行身份验证；
 * - 定义 HTTP 请求的安全规则，包括登录页面、权限控制以及 URL 访问策略；
 * - 支持基于角色或权限的访问控制，确保只有经过认证的用户才能访问受保护资源；
 * - 提供简单的表单登录支持，并允许部分路径无需认证（如登录页）；
 * - 关闭默认的 CSRF 保护机制，适用于不使用 Cookie/Session 的状态化认证方式（如 JWT）。
 *
 *
 * @author xiaopeng
 * @version 1.0
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsServiceImpl userDetailsServiceImpl;

    /**
     * 配置AuthenticationManagerBuilder以使用自定义的UserDetailsService
     *
     * @param auth AuthenticationManagerBuilder实例，用于配置认证管理器
     * @throws Exception 配置过程中可能抛出的异常
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsServiceImpl);
    }

    /**
     * 配置HttpSecurity以定义Web安全特性
     *
     * @param http HttpSecurity实例，用于配置HTTP请求的安全约束
     * @throws Exception 配置过程中可能抛出的异常
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义表单登录，登录页面为/login.html
        // 表单登录成功后，会在Cookie中存放内容：
        /*
        HTTP Cookie 的值，通常用于客户端与服务器之间的会话管理。它包含多个键值对，每个键值对以分号 ; 分隔。以下是该 Cookie 中各个字段的解析：
            username=admin：表示当前登录用户的用户名为 admin。
            rememberMe=true：表示用户选择了“记住我”功能，服务器可能会延长该用户的登录状态。
            password=Q0U5e1akuncHVkrZ2U9k...o5PNqZeShw==：这是加密后的密码（可能是 Base64 或某种加密算法处理过的字符串），
            不建议在 Cookie 中直接存储密码，即使加密过也存在安全风险。
            Idea-253abb0d=1717ee7e-5b35-45be-8813-7f8e15be5989：这可能是 JetBrains IDE 的插件或服务使用的会话标识符。
            JSESSIONID=45CA6F117484599C33CE2FA42DD52D6A：Java Web 应用的标准会话标识符，用于跟踪用户的会话。
        * */
        http.formLogin()
                .loginPage("/login.html") //自定义登录页面
                .usernameParameter("username")// 表单中的用户名项
                .passwordParameter("password")// 表单中的密码项
                .loginProcessingUrl("/login") // 登录路径，表单向该路径提交，提交后自动执行UserDetailsService的方法
                .successForwardUrl("/main")//登录成功后跳转的路径
                .failureForwardUrl("/fail");//登录失败后跳转的路径

        // 配置需要认证的资源
        http.authorizeRequests()
                .antMatchers("/login.html").permitAll()  //放行，登录页不需要认证
                .antMatchers("/fail").permitAll()
                .antMatchers("/main").permitAll()


                .antMatchers("/user/findAll").permitAll()



//                .antMatchers("/user/findAll").hasAnyAuthority("system:manage")

                /*
                 注解权限:
                     除了配置类，在SpringSecurity中提供了一些访问控制的注解。这些注解默认都是不可用的，需要开启后使用。
                    1. 启动类添加开启注解
                        @EnableGlobalMethodSecurity(securedEnabled=true)
                    2. @Secured
                        该注解是基于角色的权限控制，要求UserDetails中的权限名必须以 ROLE_ 开头。
                        @Secured("ROLE_reportform")
                        @GetMapping("/reportform/find")
                        public String findReportForm() {
                            return "查询报表";
                        }

                    3. @PreAuthorize
                        该注解可以在方法执行前判断用户是否具有权限
                        @EnableGlobalMethodSecurity(prePostEnabled = true)
                        @PreAuthorize("hasAnyAuthority('/reportform/find')")
                        @GetMapping("/reportform/find")
                        public String findReportForm() {
                            return "查询报表";
                        }
                * */

                //其余所有请求都需要认证
                .anyRequest().authenticated();

        //关闭csrf防护
        http.csrf().disable();
    }
}

